#pragma once
#include <iostream>
#include <cassert>
#include "reverse_iterator.h"
using namespace std;

namespace test
{
template<class T>
struct __list_node
{
    __list_node<T>* _prev;
    __list_node<T>* _next;
    T _data;

    __list_node<T>(const T& t = T())
        : _data(t)
    {}

    __list_node<T>(T&& t)
        : _data(std::forward<T>(t))
    {}
};

template<class T, class Ref, class Ptr>
struct __list_iterator
{
    typedef __list_node<T> list_node;
    typedef __list_iterator<T, Ref, Ptr> self;

    __list_iterator(list_node* n)
        : _node(n)
    {}

    Ref operator*()
    {
        return _node->_data;
    }

    Ptr operator->()
    {
        return &_node->_data;
    }

    self& operator++()
    {
        _node = _node->_next;
        return *this;
    }

    self& operator--()
    {
        _node = _node->_prev;
        return *this;
    }

    bool operator!=(const self& s)
    {
        return _node != s._node;
    }

    list_node* _node;
};

template<class T>
struct list
{
public:
    typedef __list_node<T> list_node;
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;

    typedef reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;
    typedef reverse_iterator<iterator, T&, T*> reverse_iterator;

public:
    iterator begin() { return iterator(_head->_next); }
    iterator end() { return iterator(_head); }

    const_iterator begin() const { return const_iterator(_head->_next); }
    const_iterator end() const { return const_iterator(_head); }

    reverse_iterator rbegin() { return reverse_iterator(end()); }
    reverse_iterator rend() { return reverse_iterator(begin()); }

    const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
    const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }

    void empty_init()
    {
        _head = new list_node;
        _head->_prev = _head;
        _head->_next = _head;
    }

    void swap(list<T>& lt)
    {
        std::swap(_head, lt._head);
    }

    list<T>()
    {
        empty_init();
    }

    template<class Iterator>
    list<T>(Iterator first, Iterator last)
    {
        empty_init();
        while (first != last)
        {
            push_back(*first);
            ++first;
        }
    }

    list<T>(const list<T>& lt)
    {
        empty_init();
        list<T> tmp(lt.begin(), lt.end());
        swap(tmp);
    }

    list<T>& operator=(list<T> lt)
    {
        if (this != &lt)
        {
            swap(lt);
        }
        return *this;
    }

    void clear()
    {
        iterator it = begin();
        while (it != end())
        {
            it = erase(it);
        }
    }

    ~list<T>()
    {
        clear();
        delete _head;
    }

    iterator insert(iterator pos, const T& x)
    {
        list_node* new_node = new list_node(x);
        list_node* prev     = pos._node->_prev;
        list_node* next     = pos._node;

        new_node->_prev = prev;
        prev->_next = new_node;
        new_node->_next = next;
        next->_prev = new_node;
        return iterator(new_node);
    }

    iterator insert(iterator pos, T&& x)
    {
        list_node* new_node = new list_node(std::forward<T>(x));
        list_node* prev     = pos._node->_prev;
        list_node* next     = pos._node;

        new_node->_prev = prev;
        prev->_next = new_node;
        new_node->_next = next;
        next->_prev = new_node;
        return iterator(new_node);
    }

    iterator erase(iterator pos)
    {
        list_node* prev = pos._node->_prev;
        list_node* next = pos._node->_next;

        prev->_next = next;
        next->_prev = prev;
        delete pos._node;
        return iterator(next);
    }

    void push_back(const T& x)
    {
        cout << "void push_back(const T&)" << endl;
        insert(end(), x);
    }

    void push_back(T&& x)
    {
        cout << "void push_back(const T&&)" << endl;
        insert(end(), std::forward<T>(x));
    }

    // void push_back(T&& x) {
    //     cout << "void push_back(const T&&)" << endl;
    //     insert(end(), x);
    // }

    void push_front(const T& x) { insert(begin(), x); }

    void pop_back() { erase(--end()); }

    void pop_front() { erase(begin()); }

    void print()
    {
        for (auto e : *this)
        {
            cout << e << "";
        }
        cout << endl;
    }

private:
    list_node* _head;
};

}